/* Copyright 2001,2002,2003 NAH6 BV
 * All Rights Reserved
 *
 *  $Header: /var/lib/cvs/secphone/ui/ce/CPhone.cpp,v 1.21 2003/11/21 12:39:24 itsme Exp $
 *
 *  this module contains the main application startup and initialization code.
 *
 *
 */

#include <afxwin.h>

#include "CPhone.h"

#include "PhoneOptions.h"

#include "CPhoneDlg.h"
#include "debug.h"
#include "killapp.h"    // KillIexplorerLinkApp

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include "fnaPRNG.h"

#include "esrcCryptoApi.h"
#include "esrcMousePosition.h"
#include "esrcAudioInput.h"

#include "UserdataHandler.h"
#include "DiffieHellmanHandler.h"
#include "SpipcHandler.h"
#include "PhoneHandler.h"
#include "UDCAutoAnswer.h"
#include "CallProgressSignalling.h"
#include "ConfigManager.h"
#include "VolumeManager.h"
#include "ThreadMonitor.h"

#ifdef _WIN32_WCE   // not for the desktop version
#include "UDCLicenseHandler.h"
#include "SpPimHandler.h"
#include "RilClass.h"
#endif

#include "BatteryClass.h"

#include "UDCPinger.h"

#include "Configuration.h"
#include "stringutils.h"

/////////////////////////////////////////////////////////////////////////////
// CCPhoneApp

BEGIN_MESSAGE_MAP(CCPhoneApp, CWinApp)
    //{{AFX_MSG_MAP(CCPhoneApp)
        // NOTE - the ClassWizard will add and remove mapping macros here.
        //    DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCPhoneApp construction

CCPhoneApp::CCPhoneApp()
    : CWinApp()
{
    DebugOutputDebugString();
    DebugSetLogfile("sp.log");

    debug("Starting phone app, compiled with msc version %d  running windows version %04x\n",  _MSC_VER, WINVER);
    m_rng= NULL;
    m_audioinput= NULL;
    m_ud= NULL;
    m_dh= NULL;
    m_ipc= NULL;
    m_cfgmgr= NULL;
    m_pinger= NULL;
    m_phone= NULL;
    m_aa= NULL;
    m_cptone= NULL;
    m_batt= NULL;

#ifdef _WIN32_WCE
    m_lic= NULL;
    m_ril= NULL;
    m_pimhandler= NULL;
#endif
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CCPhoneApp object

CCPhoneApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CCPhoneApp initialization

BOOL CCPhoneApp::InitInstance()
{
    CWnd *pParent= NULL;

#ifdef _WIN32_WCE

    ImmDisableIME(0);

    // create parent window for dialog, see
    // http://www.pocketpcdn.com/qa/today_friendly_dialogs.html for reason.
    // we need an invisible window as parent, otherwise the today dialog will
    // not work properly anymore.
    CString strParentClass;
    CWnd objParentWindow;
    strParentClass = AfxRegisterWndClass(0);
    objParentWindow.CreateEx(0, strParentClass, ::AfxGetAppName(), 
                0, -1, -1, 0, 0,   0, 0);
    // ( ..., style, x, y, w, h,   parent, id )

    pParent= &objParentWindow;
#endif

    LoadConfiguration();

    // ... not nescesary if we do not want the 'secure:' url handler
    //SetupRegistryKeys();

    debug("starting main dialog\n");

#ifdef _USE_DOMODAL
    CCPhoneDlg dlg(pParent);        m_dlg= &dlg;
#else
    CCPhoneDlg dlg;                 m_dlg= &dlg;
// --- my 'DoModal' replacement
    if (!dlg.Create(IDD_CPHONE_DIALOG, pParent))
    {
        debug("ERROR creating dialog\n");
        return FALSE;
    }
#ifdef _WIN32_WCE
    // pimhandler should be created after the dialog.
    SpPimHandler pim;               m_pimhandler= &pim;
#endif

    // should process commandline after dialog has been created
    if (AfxGetApp()->m_lpCmdLine)
        ParseCommandLine(AfxGetApp()->m_lpCmdLine);

    debug("dialog created\n");
#endif

    PRNG rng;                       m_rng= &rng;

    m_rng->AddSource(new esrcCryptoApi());
    m_rng->AddSource(new esrcMousePosition());

    m_audioinput= new esrcAudioInput();
    m_rng->AddSource(m_audioinput);

    UserdataHandler ud(dlg);        m_ud= &ud;
    DiffieHellmanHandler dh(dlg);   m_dh= &dh;
    SpipcHandler ipc(dlg);          m_ipc= &ipc;
    m_ipc->Init();

    ConfigManager cfgmgr;           m_cfgmgr= &cfgmgr;
    m_cfgmgr->Init();
    UDCPinger ping(dlg);            m_pinger= &ping;
    PhoneHandler phone(dlg);        m_phone= &phone;
	
    UDCAutoAnswer aa(dlg);          m_aa= &aa;
#ifdef _WIN32_WCE
    //UDCLicenseHandler lic(dlg);     m_lic= &lic;
#endif
    CallProgressSignalling cptone(dlg); m_cptone= &cptone;
    VolumeManager volmgr;           m_volmgr= &volmgr;

#ifdef _USE_THREADMONITOR
    ThreadMonitor threadmon;        m_threadmon= &threadmon;
#endif

    BatteryClass batt;              m_batt= &batt;

#ifdef _WIN32_WCE
    RilClass ril;                   m_ril= &ril;
    ril.open(1);

    ril.RequestIMEI();          // this should check the license
#endif
    
    // --------------------------------------------------
    // start threads here

    debug("starting rng thread\n");
    m_rng->StartThread();
    
    debug("starting dh threads\n");
    m_dh->StartThread();
    
    debug("starting phone thread\n");
    m_phone->StartThread();
    
    debug("starting cptone threads\n");
    m_cptone->StartThread();

    debug("starting volumemanager thread\n");
    m_volmgr->StartThread();

#ifdef _USE_THREADMONITOR
    debug("starting threadmonitor thread\n");
    m_threadmon->StartThread();
#endif
	int saa = KillApp(L"cprog.exe");
    debug("threads started\n");

    // the vibrator thread is started from the callprogress object
    // the calculator thread is started from the diffiehellman object


#ifdef _USE_DOMODAL
    dlg.DoModal();
#else
//--- my 'DoModal' replacement
    while (!dlg.PumpMessages())
    {
        // nothing
    }
#endif
    m_ipc->Stop();

    return FALSE;
}


// see if app is already running, in that case post commandline with
// copydata message to original application.
BOOL CCPhoneApp::InitApplication() 
{
    CWnd *appwnd= CWnd::FindWindow(NULL, L"CryptoPhone");

    if (appwnd)
    {
        COPYDATASTRUCT cd;
        cd.cbData= (_tcslen(this->m_lpCmdLine)+1)*sizeof(TCHAR);
        cd.dwData= 0;
        cd.lpData= this->m_lpCmdLine;
        appwnd->SendMessage(WM_COPYDATA, 0, (DWORD)&cd);
    }

    return CWinApp::InitApplication();
}

void msgerror(const std::string& message)
{
    MessageBox(0, ToWString(message).c_str(), L"ERROR", 0);
}

#define HANDLESTRCOMBIOPTION(var) (arg[2] ? !(var= arg.substr(2)).empty() : i+1 != args.end() ? !(var= *(++i)).empty() : 0)
#define HANDLESTROPTION(var) (i+1 != args.end() ? !(var= *(++i)).empty() : 0)

bool CCPhoneApp::ParseCommandLine(TCHAR *cmdline)
{
    if (cmdline==NULL)
        return true;

    // split the commandline in separate arguments.
    StringList args;
    if (!SplitString(ToString(cmdline), args, false))
    {
        msgerror("Error in commandline");
        return false;
    }

#ifdef _WIN32_WCE
    // these are the parameters we are parsing from the commandline
    std::string urlstring;
    std::string objectid;
#endif

    // parse the list
    int argsfound=0;
    for (StringList::iterator i= args.begin() ; i!=args.end() ; ++i)
    {
        std::string& arg= *i;
        if (arg[0]=='-') switch(arg[1])
        {
#ifdef _WIN32_WCE
        case 'u': 
            if (arg=="-url")
                if (!HANDLESTROPTION(urlstring))
                {
                    msgerror("Error in commandline: -url needs a parameter");
                    return false;
                }
            break;
        case 'o': 
            if (arg=="-oid")
                if (!HANDLESTROPTION(objectid))
                {
                    msgerror("Error in commandline: -oid needs a parameter");
                    return false;
                }
            break;
#endif
        default:
            msgerror(stringformat("unknown commandline option: %s", arg.c_str()));
            return false;
        }
        else switch(argsfound++)
        {
        case 0:
        default:
            msgerror(stringformat("unknown commandline argument: %s", arg.c_str()));
            return false;
        }
    }
#ifdef _WIN32_WCE
    if (!urlstring.empty())
    {
        if (urlstring.size()>7 && urlstring.substr(0,7)=="secure:")
        {
            m_dlg->ClearPartner();
            m_dlg->SetNumber(urlstring.substr(8));
            m_dlg->SetForegroundWindow();
        }
        KillIexplorerLinkApp();
    }
    if (!objectid.empty())
    {
        m_pimhandler->DialObjectId((CEOID)strtoul(objectid.c_str(), 0, 16));
    }
#endif
    return true;
}


void CCPhoneApp::RunReseedApp()
{
    // todo: maybe notify user by displaying a dialog?
    // or maybe just display a notification in the dialog.
    m_audioinput->StartAudioInput();

    // this causes 2*44100 bytes of audio data to be
    // hashed and added to the accumulator
    Sleep(16000);
    m_audioinput->StopAudioInput();
}

